//===============================================================================
//
// VisualStudioProjectFileCollection
//
// PURPOSE: 
// 
//
// NOTES: 
// 
//
//===============================================================================
//
// Copyright (C) 2003 Wallis Software Solutions
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.
//
//===============================================================================

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Agile.Common;

namespace Agile.Genie.Descriptors
{
    /// <summary>
    /// VisualStudioProjectFileCollection
    /// </summary>
    public class VisualStudioProjectFileCollection : IEnumerable
    {
        private readonly ArrayList _loadedDirectories = new ArrayList();

        private readonly Dictionary<string, VisualStudioProjectFile> projectFiles =
            new Dictionary<string, VisualStudioProjectFile>();

        /// <summary>
        /// Returns the total number of items that are in the collection
        /// </summary>
        public int Count
        {
            get { return projectFiles.Count; }
        }

        /// <summary>
        /// Returns the VisualStudioProjectFile that is at the given index in the collection.
        /// </summary>
        public VisualStudioProjectFile this[string key]
        {
            get { return projectFiles[key]; }
        }

        #region IEnumerable Members

        /// <summary>
        /// Gets the VALUES enumerator by default
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return projectFiles.Values.GetEnumerator();
        }

        #endregion

        /// <summary>
        /// Gets the project from the collection that has the given project guid
        /// Returns null if no match is found.
        /// </summary>
        /// <param name="guid">GUID of the project to find.</param>
        /// <returns></returns>
        public VisualStudioProjectFile GetByProjectGuid(Guid guid)
        {
            foreach (VisualStudioProjectFile project in this)
            {
                if (project.ProjectGuid.Equals(guid))
                    return project;
            }
            return null;
        }

        /// <summary>
        /// Gets the project from the collection that has the given 
        /// assembly name.
        /// Returns null if no match is found.
        /// </summary>
        /// <param name="assemblyName">Assembly name of the project to find.</param>
        /// <returns></returns>
        public VisualStudioProjectFile GetByAssemblyName(string assemblyName)
        {
            foreach (VisualStudioProjectFile project in this)
            {
                if (project.ProjectAssemblyName.Equals(assemblyName))
                    return project;
            }
            return null;
        }

        /// <summary>
        /// Gets the project from the collection where the assembly name
        /// ends with the given string. (essentially a 'soft' search).
        /// Returns null if no match is found.
        /// </summary>
        /// <remarks>Only use this search after first looking for the full AssemblyName.</remarks>
        /// <param name="endsWith">string the Assembly name of the project must end with.</param>
        /// <returns></returns>
        public VisualStudioProjectFile GetByAssemblyNameSoftSearch(string endsWith)
        {
            foreach (VisualStudioProjectFile project in this)
            {
                if (project.ProjectAssemblyName.EndsWith(endsWith))
                    return project;
            }
            return null;
        }

        /// <summary>
        /// Checks if the projects have been already loaded for the given directory.
        /// </summary>
        /// <param name="directory"></param>
        /// <returns>True if the projects have been loaded.</returns>
        public bool HaveProjectsBeenLoaded(DirectoryInfo directory)
        {
            foreach (object dir in _loadedDirectories)
            {
                if (((DirectoryInfo) dir).FullName.Equals(directory.FullName))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Loads all of the project files in the given directory.
        /// </summary>
        /// <param name="directory"></param>
        public void LoadProjectFilesIn(DirectoryInfo directory)
        {
            if (HaveProjectsBeenLoaded(directory))
                return;
            _loadedDirectories.Add(directory);
            Files.LoopThroughSubDirectories(directory, CheckFilesIn, "bin", "obj");
        }

        /// <summary>
        /// Check the files in the directory.
        /// </summary>
        /// <param name="directory"></param>
        private void CheckFilesIn(DirectoryInfo directory)
        {
            Files.GoThroughFilesIn(directory, LookForProjectFile);
        }

        /// <summary>
        /// Check if the file is a project file, if it is, add it to the cache.
        /// </summary>
        /// <param name="file">File to check</param>
        private void LookForProjectFile(FileInfo file)
        {
            if (Files.IsTheRightFileType(file, "csproj", "vbproj"))
            {
                VisualStudioProjectFile project = VisualStudioProjectFileFactory.InstantiateFrom(file);
                // Add to the cache
                VisualStudioProjectFileCache.GetInstance().LoadedProjectFiles.Add(project);
            }
        }

        /// <summary>
        /// Adds the items in the collection to the existing collection.
        /// </summary>
        public void AddRange(VisualStudioProjectFileCollection projectFilesToAdd)
        {
            foreach (VisualStudioProjectFile visualStudioProjectFile in projectFilesToAdd)
                Add(visualStudioProjectFile);
        }

        /// <summary>
        /// Add a new VisualStudioProjectFile to the collection
        /// </summary>
        public void Add(string projectName, VisualStudioProjectFile visualStudioProjectFile)
        {
            projectFiles[projectName] = visualStudioProjectFile;
        }

        /// <summary>
        /// Add a new VisualStudioProjectFile to the collection
        /// </summary>
        public void Add(VisualStudioProjectFile visualStudioProjectFile)
        {
            projectFiles[visualStudioProjectFile.ProjectName] = visualStudioProjectFile;
        }

        /// <summary>
        /// Remove a VisualStudioProjectFile from the collection
        /// </summary>
        public void Remove(string projectName)
        {
            projectFiles.Remove(projectName);
        }


        /// <summary>
        /// Checks if the given Project is in the collection
        /// </summary>
        /// <returns>True if the item is in the collection.</returns>
        public bool Contains(string projectName)
        {
            return projectFiles.ContainsKey(projectName);
        }

        #region Constructors and Factories

        /// <summary>
        /// Constructor
        /// </summary>
        internal VisualStudioProjectFileCollection()
        {
        }

        /// <summary>
        /// Instantiate a new VisualStudioProjectFileCollection
        /// </summary>
        public static VisualStudioProjectFileCollection Build()
        {
            return new VisualStudioProjectFileCollection();
        }

        #endregion
    }
}